#***********************************************************
#* Copyright (c) 2006, Zhimin Zhan.
#* Distributed open-source, see full license in MIT-LICENSE
#***********************************************************

require 'watir/watir_simple.rb'
require 'runit/assert'

module RWebUnit

##
#  Wrapping WATIR and provide assertions
#
class WebTester 
  include Watir::Simple
  include RUNIT::Assert

  attr_accessor :test_context

  def initialize
    @test_context = TestContext.new
  end

  def beginAt(relativeURL)
    url = @test_context.base_url  + relativeURL
    new_browser_at(url) # create @@browser
  end

  def closeBrowser
    begin
     close_browser
    rescue 
    end
  end


  def goBack
    go_back()
  end

  def goForward
    go_forward()
  end

  def gotoPage(page)
    navigate_to(page)
  end

  # assertions
  def assertTitleEquals(title)
    assert_equals(title, html_title())
  end

  # text fields
  def setFormElement(elementName, elementValue)
     enter_text_into_field_with_name(elementName, elementValue)
  end
  alias enterText setFormElement

  def assertTextPresentInTextField(textfieldName, text, msg = nil)
    assert_text_in_field(textfieldName, text, msg)
  end

  #links
  def clickLink(linkId)
    click_link_with_id(linkId)
  end

  def clickLinkWithText(linkText)
    click_link_with_text(linkText)
  end

  def assertLinkPresentWithText(linkText)
    html_links.each { |link|
      return if linkText == link.text
    }
    assert(false, "can't find the link with text: #{linkText}")
  end

  def assertLinkNotPresentWithText(linkText)
    html_links.each { |link|
      assert(linkText != link.text, "unexpected link: #{linkText} found")
    }
  end

  ##
  # buttons

  # submit first submit button
  def submit(buttonName = nil)
    if (buttonName.nil?) then
      html_buttons.each { |button|
        next if button.type != 'submit'
        button.click
        return
      }
    else
      click_button_with_name(buttonName)
    end
  end

  def clickButton(buttonId)
    click_button_with_id(buttonId)
  end

  def clickButtonWithCaption(caption)
    click_button_with_caption(caption)
  end

  def clickButtonWithValue(value)
    click_button_with_value(value)
  end

  def assertButtonNotPresent(buttonId)
   html_buttons.each { |button|
     assert(button.id != buttonId, "unexpected button id: #{buttonId} found")
   }
  end

  def assertButtonNotPresentWithText(text) 
   html_buttons.each { |button|
     assert(button.value != text, "unexpected button id: #{text} found")
   }
  end
 
  def assertButtonPresent(buttonID) 
   html_buttons.each { |button|
      return if buttonID == button.id
   }
   assert(false, "can't find the button with id: #{buttonID}")
  end

  def assertButtonPresentWithText(buttonText)
   html_buttons.each { |button|
      return if buttonText == button.value
   }
   assert(false, "can't find the button with text: #{buttonText}")
  end

  # checkbox
  def checkCheckbox(checkBoxName)
    @@browser.checkbox(:name, checkBoxName).set
  end

  def uncheckCheckbox(checkBoxName)
    @@browser.checkbox(:name, checkBoxName).clear
  end

  def assertCheckboxNotSelected(checkBoxName)
    rasie
  end

  def assertCheckboxSelected(checkBoxName)
    raise
  end


  # combo box
  def selectOption(selectName, option)
    @@browser.select_from_combobox_with_name(selectName, option)
  end

  def assertOptionValueNotPresent(selectName, optionValue)
    html_selects.each { |select|
      select.o.each do |option| # items in the list
        assert(!(select.name == selectName && option.value == optionValue), "unexpected select option: #{optionValue} for #{selectName} found")
      end
    }
  end

  def assertOptionNotPresent(selectName, optionLabel)
    html_selects.each { |select|
      select.o.each do |option| # items in the list
        assert(!(select.name == selectName && option.text == optionLabel), "unexpected select option: #{optionLabel} for #{selectName} found")
      end
    }
  end

  def assertOptionValuePresent(selectName, optionValue)
    html_selects.each { |select|
     select.o.each do |option| # items in the list
       return if (select.name == selectName && option.value == optionValue)
      end
    }
    assert(false, "can't find the combob box with value: #{optionValue}")
  end

  def assertOptionPresent(selectName, optionLabel)
    html_selects.each { |select|
     select.o.each do |option| # items in the list
       return if (select.name == selectName && option.text == optionLabel)
      end
    }
    assert(false, "can't find the combob box: #{selectName} with value: #{optionLabel}")
  end

  #text
  def assertTextPresent(text)
    puts html_body() if $DEBUG
    assert((html_body().include? text), 'expected text: ' + text + ' not found')
  end

  def assertTextNotPresent(text)
    assert(!(html_body().include? text), 'expected text: ' + text + ' found')
  end

  def assertElementPresent(elementID)
     elem = @@browser.document.getElementById(elementID)
     assert_not_nil(elem)
  end

  def assertElementNotPresent(elementID)
     elem = @@browser.document.getElementById(elementID)
     assert_nil(elem)
  end

  def assertTextInElement(elementID, text)
    elem = @@browser.document.getElementById(elementID)
    assert_not_nil(elem.innerText)
    assert(elem.innerText.include?(text))
  end

  def getElementValue(elementId)
    elem = @@browser.document.getElementById(elementId)
    return nil if elem == nil
    elem_val = elem.invoke('innerText')
    return elem_val
  end

  # ---
  # For deubgging
  # ---
  def dumpResponse(stream = nil)
    if stream.nil?
      puts html_body # std out
    else
      stream.puts html_body
    end
  end

private
  def html_body
    @@browser.html()
  end

  def html_title
    @@browser.document.title
  end

  def html_links
    @@browser.links
  end

  def html_buttons
    @@browser.buttons
  end

  def html_selects
    @@browser.select_lists
  end

  def assert_equals(expected, actual, msg=nil)
    assert(expected == actual, (msg.nil?) ? "Expected: #{expected} diff from actual: #{actual}" : msg)
  end
  alias assert_equal assert_equals

  def assert_nil(actual, msg="")
    assert(actual.nil?, msg)
  end

  def assert_not_nil(actual, msg="")
    assert(!actual.nil?, msg)
  end

end

end